/******************************************************************************
 *  _____     _____
 *  \  __\    \  __\
 *   \ \_\\    \ \_\\
 *    \  __\SS  \  __\roject
 *     \_\       \_\
 *
 * Mateusz Maciąg, Rafał Urbański
 * Komputerowe Systemy Sterowania
 *****************************************************************************/

#ifndef RSTController_H
#define RSTController_H

#include "ControllerBase.h"
#include "Adaptive/AdaptiveAlgorithmBase.h"

// Przestrzeń nazw
namespace RafMat
{
namespace SimEngine
{

// Deklaracja zapowiadająca
class AdaptiveAlgorithmBase;

/**
    Ogólny regulator dyskretny o równaniu Ru + Sy - Tw - h = 0

    Regulator stworzony na potrzeby regulacji adaptacyjnej.
    Wielomiany R, S, T mogą być zadawane ręcznie (dla testów)
    Lub przez obiekty realizujące część adaptacyjną.
*/
class RSTController : public ControllerBase
{
public:
    typedef SimInterface::ISimulator::AdptType AdptType;

    /**
        Konstruktor testowego pseudoregulatora.
        Konstruktor wiąże regulator z konkretnym obiektem symulatora.

        \param [in] isim Obiekt symulatora-właściciela tego regulatora.
    */
    explicit RSTController(SimInterface::ISimulator &isim);

    //
    // Implementacja IConfigurable
    //

    /**
        Funkcja ustawiająca parametry regulatora za pomocą łańcuchów znakowych.

        Wspierane parametry:
        - adptype - typ regulatora adaptacyjnego - zmiana powoduje wywołanie createAlgorithm()
        - adpt::* - ustawienia specyficzne algorytmu (w miejsce *)

        \param [in] param Parametr, który chcemy zmienić (jeden z wymienionych).
        \param [in] value Wartość, którą przypisujemy parametrowi.
        \return True jeśli operacja się powiodła.
        \throws std::logic_error, gdy wykryty zostanie błąd (argumentu lub strumienia danych).
    */
    bool setParameter(const std::string& param, const std::string& value) throw(std::logic_error);

    /**
        Funkcja pobiera parametry regulatora P w postaci łańcuchów znakowych.

        Wspierane parametry są takie same jak w setParameter().

        \param [in] param Parametr, który chcemy odczytać.
        \return Łańcuch reprezentujący wartość parametru.
        \throws std::logic_error, gdy wykryty zostanie błąd (argumentu lub strumienia danych).
    */
    std::string getParameter(const std::string& param) const throw(std::logic_error);

    /**
        Resetuje regulator.
    */
    void reset();

    /**
        Wymusza zmianę rozmiarów buforów próbek, jeśli są zbyt małe dla wielomianów
        zwracanych przez obiekt adaptacyjny.
    */
    void resizeBuffersIfNecessary();

protected:

    /**
        Realizuje krok regulacji.

        Funkcja implementuje abstrakcyjną metodę z klasy bazowej ControllerBase.
        Realizuje równanie modelu regulatora RST.

        \param [in] setPoint Wartość zadana.
        \param [in] processVar Wartość zmiennej procesowej (np. ze sprzężenia zwrotnego).
        \return Wartość wyjścia regulatora.
    */
    double simulateControllerStep(double setPoint, double processVar);

    SimFile::ConfigWriter& dumpSpecificPar(SimFile::ConfigWriter& o) const;

private:
    static const std::string CONF_ADPTTYPE;
    static const std::string CONF_ADPTINDEX;
    static const std::string CONF_ADPSETTINGS;

    /** Tworzy nowy algorytm na żądanie użytkownika.
        Wywoływane przez setParameters
    */
    void createAlgorithm(AdptType adptType = SimInterface::ISimulator::AdptTypeStatic);

    std::deque<double> m_umem;          ///< Pamięć dla wyjściowych (sterowanie u(i)).
    std::deque<double> m_wmem;          ///< Pamięć dla próbek wejściowych (w. zadana w(i)).
    std::deque<double> m_ymem;          ///< Pamięć dla próbek wejściowych (w. procesowa y(i)).

    // Blok odpowiedzialny za adaptację.
    AdaptiveAlgorithmBaseSPtr m_adpt;

    // Zmapowane wartości - nazwa algorytmu -> odpowiedni enum.
    std::map<std::string, AdptType> m_strToAdpt;
};

}
}

#endif // RSTController_H
